// MainMenuSubclass.cpp: implementation of the CMainMenuSubclass class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MainMenuSubclass.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

CMenuItem::CMenuItem(CMenu* pMainMenu, int nIndex, CMainMenuSubclass* pMainMenuSubclass)
{
	m_pMenuSub = pMainMenu->GetSubMenu(nIndex);

	m_rcItem.SetRect(pMainMenuSubclass->m_rcBound.left + nIndex * 50, 
			pMainMenuSubclass->m_rcBound.top,
				pMainMenuSubclass->m_rcBound.left + (nIndex + 1) * 50,
					pMainMenuSubclass->m_rcBound.bottom);
	m_fsState = IS_NORMAL;

	TCHAR szText[256];
	MENUITEMINFO info; ::memset(&info, 0, sizeof(MENUITEMINFO));
	info.cbSize		= sizeof(MENUITEMINFO);
	info.fMask		= MIIM_ID | MIIM_TYPE;
	info.dwTypeData = szText;
	info.cch		= sizeof(szText);
	pMainMenu->GetMenuItemInfo(nIndex, &info, TRUE);
	m_strCaption = CString(szText);

	SetOwnerDraw(m_pMenuSub);
}

CMenuItem::~CMenuItem()
{
	UnsetOwnerDraw(m_pMenuSub);
}

void CMenuItem::OnPaint(CDC* pDC)
{
	if (m_fsState == IS_NORMAL) {
		
	} else if (m_fsState == IS_FOCUS) {
		CBrush brush(RGB(0, 255, 0));
		pDC->FillRect(&m_rcItem, &brush);
	} else if (m_fsState == IS_PRESSED) {
		CBrush brush(RGB(0, 255, 255));
		pDC->FillRect(&m_rcItem, &brush);
	}
	pDC->SetBkMode(TRANSPARENT);
	pDC->DrawText(m_strCaption, m_strCaption.GetLength(), &m_rcItem, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}

void CMenuItem::TrackPopup(CWnd* pMainWnd)
{
	CRect rcWin;
	pMainWnd->GetWindowRect(&rcWin);
	CPoint ptPopup(m_rcItem.left + rcWin.left, m_rcItem.bottom + rcWin.top);
		//::TrackPopupMenuEx(m_hSubMenu, fuFlags,
		//pt.x, pt.y, pWndSentCmd->GetSafeHwnd(), &tpm);
	m_pMenuSub->TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON,
		ptPopup.x, ptPopup.y, pMainWnd);

}

void CMenuItem::SetOwnerDraw(CMenu* pMenu)
{
	for(int i = 0; i < pMenu->GetMenuItemCount(); i ++) {
		UINT id = pMenu->GetMenuItemID(i);
		if ( id == -1) {
			CMenu* pSubMenu = pMenu->GetSubMenu(i);
			SetOwnerDraw(pSubMenu);
		}
		TCHAR* szText = new TCHAR[MAX_PATH];
		::memset(szText, 0, MAX_PATH);
		MENUITEMINFO info; 
		::memset(&info, 0, sizeof(MENUITEMINFO));
		info.cbSize		= sizeof(MENUITEMINFO);
		info.fMask		= MIIM_ID | MIIM_TYPE;
		info.dwTypeData = szText;
		info.cch		= MAX_PATH;
		pMenu->GetMenuItemInfo(i, &info, TRUE);

		pMenu->ModifyMenu(i, MF_BYPOSITION | MF_OWNERDRAW, id, (LPCTSTR)szText);
	}
}

void CMenuItem::UnsetOwnerDraw(CMenu* pMenu)
{
	//TRACE("In void CMenuItem::UnsetOwnerDraw(CMenu* pMenu)");
	for(int i = 0; i < pMenu->GetMenuItemCount(); i ++) {
		UINT id = pMenu->GetMenuItemID(i);
		if ( id == -1) {
			CMenu* pSubMenu = pMenu->GetSubMenu(i);
			UnsetOwnerDraw(pSubMenu);
		}
		CString strCaption;
		pMenu->GetMenuString(i, strCaption, MF_BYPOSITION);

		pMenu->ModifyMenu(i, MF_BYPOSITION | ((strCaption=="")?MF_SEPARATOR:MF_STRING), id, (LPCTSTR)strCaption);
	}
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMainMenuSubclass::CMainMenuSubclass()
{
}

CMainMenuSubclass::~CMainMenuSubclass()
{

}

void CMainMenuSubclass::Initialization(CWnd* pMainWnd, CRect rcBound)
{
	if (!pMainWnd->GetMenu()) return;
	
	m_pWndMain = pMainWnd;
	m_pMenuMain = pMainWnd->GetMenu();
	m_rcBound = rcBound;
	m_nCurrIndex = -1;

	InitMenuItems();
}

void CMainMenuSubclass::Finalization()
{
	DeleteMenuItems();
}

BOOL CMainMenuSubclass::InitMenuItems()
{
	DeleteMenuItems();

	for (int i = 0; i < m_pMenuMain->GetMenuItemCount(); ++i) {
		m_arrMenuItem.Add(new CMenuItem(m_pMenuMain, i, this));
	}
	return TRUE;
}

void CMainMenuSubclass::DeleteMenuItems()
{
	for(int i = 0; i < m_arrMenuItem.GetSize(); ++i) {
		CMenuItem* pItem = m_arrMenuItem[i];
		delete pItem;
	}

	m_arrMenuItem.RemoveAll();
}

void CMainMenuSubclass::OnPaint(CDC* pDC)
{
	DoGradientFill(pDC, &m_rcBound);

	for(int i = 0; i < m_arrMenuItem.GetSize(); ++i) {
		CMenuItem* pItem = m_arrMenuItem[i];
		pItem->OnPaint(pDC);
	}
}

void CMainMenuSubclass::DoGradientFill(CDC *pDC, CRect* rect)
{
	CBrush brBk[64];
	int nWidth = rect->Width();	
	int nHeight = rect->Height();
	CRect rct;
	
	for (int i = 0; i < 64; i ++)
	{
		brBk[i].CreateSolidBrush(RGB(240 - (i / 3), 240 - (i / 3), 255 - (i / 5)));
	}
	
	for (i = 0; i < nHeight; i ++) 
	{
		rct.SetRect(rect->left, rect->top + i, rect->left + nWidth, rect->top + i + 1);
		pDC->FillRect(&rct, &brBk[((i * 63) / nHeight)]);
	}
	
	for (i = 0; i < 64; i ++)
		brBk[i].DeleteObject();
}

void CMainMenuSubclass::OnLButtonDown(int x, int y)
{
	int nNewIndex = PointToIndex(x, y);
	//TRACE("OnLButtonDown, You click %d th menu item", nNewIndex);
	if (nNewIndex != -1) {
		if (nNewIndex != m_nCurrIndex) {
			if (m_nCurrIndex != -1) {
				m_arrMenuItem[m_nCurrIndex]->SetState(IS_NORMAL);
			}
			m_nCurrIndex = nNewIndex;
			m_arrMenuItem[m_nCurrIndex]->SetState(IS_PRESSED);
			UpdateMainMenu();
			TrackPopup(nNewIndex);
		} else {
			if (m_arrMenuItem[m_nCurrIndex]->GetState() == IS_FOCUS){
				m_arrMenuItem[m_nCurrIndex]->SetState(IS_PRESSED);
				UpdateMainMenu();
				TrackPopup(nNewIndex);
			}
		}
	}
}

void CMainMenuSubclass::OnNcMouseMove(int x, int y)
{
	int nNewIndex = PointToIndex(x, y);
	//TRACE("OnLButtonDown, You click %d th menu item", nNewIndex);
	if (nNewIndex != -1) {
		if (nNewIndex != m_nCurrIndex) {
			if (m_nCurrIndex != -1) {
				m_arrMenuItem[m_nCurrIndex]->SetState(IS_NORMAL);
			}
			m_nCurrIndex = nNewIndex;
			m_arrMenuItem[m_nCurrIndex]->SetState(IS_FOCUS);
			UpdateMainMenu();
		} else {
			m_arrMenuItem[m_nCurrIndex]->SetState(IS_FOCUS);
			UpdateMainMenu();
		}
	} else {
		if ((m_nCurrIndex != -1) && (m_arrMenuItem[m_nCurrIndex]->GetState() == IS_FOCUS)) {
			m_arrMenuItem[m_nCurrIndex]->SetState(IS_NORMAL);
			m_nCurrIndex = -1;
			UpdateMainMenu();
		}
	}
}

int CMainMenuSubclass::PointToIndex(int x, int y)
{
	int nRet = -1;
	for(int i = 0; i < m_arrMenuItem.GetSize(); ++i) {
		CMenuItem* pItem = m_arrMenuItem[i];
		if (pItem->GetRect().PtInRect(CPoint(x, y))) {
			nRet = i;
			break;
		}
	}
	return nRet;
}

HHOOK g_hMsgHook;
CMainMenuSubclass* g_pMainMenuSubclass;

BOOL CMainMenuSubclass::OnMenuInput(MSG& m)
{
	CRect rcWnd;
	m_pWndMain->GetWindowRect(&rcWnd);
	int nMsg = m.message;
	CPoint pt = m.lParam;
	pt -= rcWnd.TopLeft();
	int nNewIndex = PointToIndex(pt.x, pt.y);

	switch (nMsg) {
	case WM_MOUSEMOVE:		
		if (nNewIndex != -1 && nNewIndex != m_nCurrIndex) {
			m_pWndMain->PostMessage(WM_CANCELMODE); 
			m_arrMenuItem[m_nCurrIndex]->SetState(IS_NORMAL);
			m_nCurrIndex = nNewIndex;
			m_arrMenuItem[m_nCurrIndex]->SetState(IS_PRESSED);
			UpdateMainMenu();
			m_bLoop = TRUE;
			m_bSelected = FALSE;
			return TRUE;
		}
		break;

	case WM_LBUTTONDOWN:
		if (nNewIndex == m_nCurrIndex) {
			m_pWndMain->SendMessage(WM_CANCELMODE); 
			m_arrMenuItem[m_nCurrIndex]->SetState(IS_NORMAL);
			UpdateMainMenu();
			//TRACE("OnMenuInput WM_LBUTTONDOWN SendMessage(WM_CANCELMODE)");
			m_bLoop = FALSE;
			m_bSelected = FALSE;
			return TRUE;
		}
		break;
	}
	return FALSE;	// pass along...
}

LRESULT CALLBACK CMainMenuSubclass::MenuInputFilter(int code, WPARAM wParam, LPARAM lParam)
{
	return (code == MSGF_MENU && g_pMainMenuSubclass->OnMenuInput( *((MSG*)lParam) )) ? TRUE : CallNextHookEx(g_hMsgHook, code, wParam, lParam);
}

void CMainMenuSubclass::TrackPopup(int nNewIndex)
{
	m_bLoop = TRUE;

	while (m_bLoop == TRUE) {
		m_bSelected = TRUE;
		m_bLoop = FALSE;
		g_hMsgHook = ::SetWindowsHookEx(WH_MSGFILTER,
			MenuInputFilter, NULL, AfxGetApp()->m_nThreadID);// m_bLoop may become TRUE
		g_pMainMenuSubclass = this;

		m_arrMenuItem[m_nCurrIndex]->TrackPopup(m_pWndMain);

		::UnhookWindowsHookEx(g_hMsgHook);
		g_pMainMenuSubclass = NULL;
		g_hMsgHook = NULL;

		if (m_bSelected) {
			m_arrMenuItem[m_nCurrIndex]->SetState(IS_NORMAL);
			m_nCurrIndex = -1;
			UpdateMainMenu();
		}
	}

	//m_arrMenuItem[nNewIndex]->TrackPopup(m_pWndMain);
}

void CMainMenuSubclass::UpdateMainMenu()
{
	CWindowDC dcWin(m_pWndMain);
	OnPaint(&dcWin);
}

void CMainMenuSubclass::SetBoundRect(CRect rcMenu)
{
	m_rcBound = rcMenu;
	UpdateMainMenu();
}

UINT CMainMenuSubclass::OnDrawItem(LPDRAWITEMSTRUCT lpDIS)
{
	CDC* pDC = CDC::FromHandle(lpDIS->hDC);
	CRect rcItem = lpDIS->rcItem;
	UINT idItem = lpDIS->itemID;
	CString strCaption((LPCTSTR)lpDIS->itemData);

	CBrush brush(RGB(200, 200, 255)	);
	pDC->FillRect(&rcItem, &brush);
	pDC->SetBkMode(TRANSPARENT);
	pDC->DrawText(strCaption, &rcItem, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
	TRACE("\nIn UINT CMainWndSubclass::OnDrawItem(LPDRAWITEMSTRUCT lpDIS) \n");
	return TRUE;
}

UINT CMainMenuSubclass::OnMeasureItem(LPMEASUREITEMSTRUCT lpMIS)
{
	lpMIS->itemHeight = 20;
	lpMIS->itemWidth = 60;
	//TRACE("\nIn UINT CMainMenuSubclass::OnMeasureItem(LPMEASUREITEMSTRUCT lpMIS) %s\n", lpMIS->itemData);
	return TRUE;
}